/* 
 * File:   AudioManager.cpp
 * Author: RedEyedKiller
 * 
 * Created on 26 Αύγουστος 2011, 8:50 μμ
 */

#include "AudioManager.h"
#include "../Logger.h"
#include "AudioSource.h"
#include "AudioCore.h"
#include "StreamSource.h"
#include <string>
#include <fstream>
#include <iostream>
#include <list>
#include <algorithm>

#ifdef __WIN32
#include <al.h>
#include <alc.h>
#else
#include <AL/al.h>
#include <AL/alc.h>
#endif

namespace al
{

namespace predicates
{

struct StreamUpdater
{
    void operator ( ) ( StreamSource * stream )
    {
        if( stream->IsPlaying( ) )
        {
            if( !stream->UpdateStream( ) )
            {
                stream->Pause( );
            }
        }
    }
};

struct SourcePauser
{
    void operator ( ) ( AbstractALSource * src )
    {
        if( src->IsPlaying( ) )
            src->Pause( );
    }
};

struct SourcePlayer
{
    void operator ( ) ( AbstractALSource * src )
    {
        if( src->IsPaused( ) )
            src->Play( );
    }
};

}

AudioManager::AudioManager()
{

}

AudioManager::~AudioManager()
{
}

bool AudioManager::Update()
{
    static predicates::StreamUpdater su;
    std::for_each( streams.begin( ), streams.end( ), su );

    KillOneTimeSounds( );

    return true;
}

AudioSource* AudioManager::CreateSource()
{
    ALuint sID = CreateSourceID( );
    if( sID )
    {
        AudioSource* src = new AudioSource( sID );

        sources.push_back( src );
        return src;
    }

    return NULL;
}

void AudioManager::KillSource(AudioSource* toKill)
{
    AudioCore::ClearErrorBuffer( );
    sources.remove( toKill );
    delete toKill;
    if( !AudioCore::Check( ) )
    {
        LOG( Logger::CHANNEL_AUDIO, LogFileStream::LEVEL_ERROR ) << "Source deletion failed.";
    }
}

StreamSource* AudioManager::CreateStream()
{
    ALuint sID = CreateSourceID( );
    if( sID )
    {
        StreamSource* stream = new StreamSource( sID );
        streams.push_back( stream );
        return stream;
    }

    return NULL;
}

void AudioManager::KillStream(StreamSource* toKill)
{
    AudioCore::ClearErrorBuffer( );
    streams.remove( toKill );
    delete toKill;
    if( !AudioCore::Check( ) )
    {
        LOG( Logger::CHANNEL_AUDIO, LogFileStream::LEVEL_ERROR ) << "Stream deletion failed.";
    }
}

void AudioManager::KillOneTimeSounds()
{
    AudioListIter it = sources.begin( );
    AudioListConstIter end = sources.end( );
    while( it != end )
    {
        if( ( *it )->IsOneTime( ) && !( *it )->IsPlaying( ) )
        {
            AudioSource* toKill = ( *it );
            ++it;
            KillSource( toKill );
        }
        else
        {
            ++it;
        }
    }
}

void AudioManager::PlayAll()
{
    static predicates::SourcePlayer sp;
    std::for_each( streams.begin( ), streams.end( ), sp );
}

void AudioManager::PauseAll()
{
    static predicates::SourcePauser sp;
    std::for_each( streams.begin( ), streams.end( ), sp );
}

unsigned int AudioManager::CreateSourceID()
{
    ALuint sID;
    AudioCore::ClearErrorBuffer( );
    alGenSources( 1, &sID );

    if( !AudioCore::Check( ) )
    {
        LOG( Logger::CHANNEL_AUDIO, LogFileStream::LEVEL_ERROR ) << "Source creation failed.";
        return 0;
    }

    return sID;
}

}
